package io.lvdaxian.mybatis14.session.defaults;

import io.lvdaxian.mybatis14.executor.Executor;
import io.lvdaxian.mybatis14.mapping.MappedStatement;
import io.lvdaxian.mybatis14.session.Configuration;
import io.lvdaxian.mybatis14.session.RowBounds;
import io.lvdaxian.mybatis14.session.SqlSession;

import java.sql.SQLException;
import java.util.List;

/**
 * DefaultSqlSession 是对象接口【SqlSession】的实现
 *
 * @author lihh
 */
public class DefaultSqlSession implements SqlSession {
  
  // 表示 控制上下文的配置文件
  private final Configuration configuration;
  // 执行器
  private final Executor executor;
  
  public DefaultSqlSession(Configuration configuration, Executor executor) {
    this.configuration = configuration;
    this.executor = executor;
  }
  
  @Override
  public <T> T selectOne(String statement) {
    return (T) this.selectOne(statement, null);
  }
  
  /**
   * 根据 statement 找到对应的sql，以及 通过参数【parameter】查询数据
   *
   * @param statement 能查询到对应sql的唯一id
   * @param parameter 实现的动态参数
   * @param <T>       动态泛型
   * @return 返回响应的值
   * @author lihh
   */
  @Override
  public <T> T selectOne(String statement, Object parameter) {
    List<T> list = this.selectList(statement, parameter);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new RuntimeException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
  }
  
  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    MappedStatement ms = configuration.getMappedStatement(statement);
    try {
      return executor.query(ms, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, ms.getSqlSource().getBoundSql(parameter));
    } catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }
  
  @Override
  public int insert(String statement, Object parameter) {
    // 在 Mybatis 中 insert 调用的是 update
    return update(statement, parameter);
  }
  
  @Override
  public int update(String statement, Object parameter) {
    MappedStatement ms = configuration.getMappedStatement(statement);
    try {
      return executor.update(ms, parameter);
    } catch (SQLException e) {
      throw new RuntimeException("Error updating database.  Cause: " + e);
    }
  }
  
  @Override
  public Object delete(String statement, Object parameter) {
    return update(statement, parameter);
  }
  
  @Override
  public void commit() {
    try {
      executor.commit(true);
    } catch (SQLException e) {
      throw new RuntimeException("Error committing transaction.  Cause: " + e);
    }
  }
  
  
  @Override
  public <T> T getMapper(Class<T> clazz) {
    return configuration.getMapper(clazz, this);
  }
  
  @Override
  public Configuration getConfiguration() {
    return configuration;
  }
}
